﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using AZROLESLib;
using AzManContrib.MVC.Html.Behaviors;

namespace AzManContrib.MVC.Html
{
    public static class LabelExtensions
    {

        /* 
         * Non generic with operation by name
         */
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, string operation)
        {
            return LabelFor(html, expression, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, string labelText, string operation)
        {
            return LabelFor(html, expression, labelText, AzMan.Application.Operations.FindByName(operation));
        }

        /* 
         * Non generic method, thus using AzMan.Defaults.UI.DenyiedBehavior 
         */
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IAzOperation operation)
        {
            Func<HtmlHelper<TModel>, Expression<Func<TModel, TValue>>, IAzOperation, MvcHtmlString> genMethod = LabelFor<TModel, TValue, HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { typeof(TModel), typeof(TValue), AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(html, new object[] { html, expression, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, string labelText, IAzOperation operation)
        {
            Func<HtmlHelper<TModel>, Expression<Func<TModel, TValue>>, string, IAzOperation, MvcHtmlString> genMethod = LabelFor<TModel, TValue, HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] {typeof(TModel), typeof(TValue), AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(html, new object[] { html, expression, labelText, operation }) as MvcHtmlString;
        }


        /* 
         * Generic methods, thus you can provide an inhibition behavior.
         */
        public static MvcHtmlString LabelFor<TModel, TValue, TBehavior>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return LabelFor<TModel, TValue, TBehavior>(html, expression, null, operation);
        }

        public static MvcHtmlString LabelFor<TModel, TValue, TBehavior>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, string labelText, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            TBehavior behavior = new TBehavior();

            if (!HttpContext.Current.User.Can(operation))
            {
                if (!behavior.ShouldRender)
                    return MvcHtmlString.Empty;
                return LabelFor(html, expression, labelText, behavior.GetHtmlAttributes(new Dictionary<string, object>()));
            }
            return System.Web.Mvc.Html.LabelExtensions.LabelFor(html, expression, labelText);
        }

        // Thanks to Imran Baloch's post : http://weblogs.asp.net/imranbaloch/archive/2010/07/03/asp-net-mvc-labelfor-helper-with-htmlattributes.aspx
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, string attributes, IDictionary<string, object> htmlAttributes)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
            string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();

            if (String.IsNullOrEmpty(labelText))
                return MvcHtmlString.Empty;

            TagBuilder tag = new TagBuilder("label");
            tag.MergeAttributes(htmlAttributes);
            tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
            tag.SetInnerText(labelText);
            return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
        }
    }
}